/****************************************************
 * File: gtklayout.c
 *
 * Author: Fred Engler
 *
 * Description: Handles the preferences for the contig
 * display setup.  Retieves the information from the 
 * fpp file.
 ****************************************************/

#include "gtklayout.h"
#include "seq.h"

#define FSCANLINE(x) fscanf(fppfile,"%1023[^\n]\n",x)

extern GtkObject *zoom_adj;
extern int track_num;
extern GtkWidget *tracks[];
extern char helpfilepath[];
extern float zoom_max;

extern FPC_TREE seq_tree;

/*                     DEF: read_fpp_file
 * Read the fpp file and put the information into 
 * the ctg_layout structure.*/
static int
read_fpp_file(){
  FILE *fppfile;
  char oneline[1024];
  int ctg=-1, bury;
  float zoom;
  int height, num_rows, type, status, chrom, attach, red, green, blue, anchor_bins, anchor_pos, anchor_lines;
  char entity[50], policy[50], name[50], remark[50], color[50];
  char help_path[MAXPATHLEN+1];
  struct layout_track_info *t_info=NULL;
  struct layout_filter_info *f_info=NULL;
  int valid=FALSE;

  if((fppfile = fopen(messprintf("%s/%s.fpp", dirName, fileName),"r")) == NULL ){
    if((fppfile = fopen(messprintf("%s.fpp", fileName),"r")) == NULL ){
	if (!Zbatch_flag)
   printf("Configuration file %s.fpp not found. Therefore will use defaults.\n",
             fileName);
	return 0;
    }
  }

  while(!feof(fppfile)){
    if(FSCANLINE(oneline)<1) goto read_error;
    if(sscanf(oneline, "<layout help_path=\"%s", help_path)==1){
      valid=TRUE;
      if(!strcmp(help_path,"\""))
        strcpy(helpfilepath, " ");
      else{
	help_path[strlen(help_path)-1]='\0';
	strcpy(helpfilepath, help_path);
      }
    }
    else if(sscanf(oneline, "<contig id=\"%d\" zoom=\"%f\" bury=\"%d\"", &ctg, &zoom, &bury)==3){
      if(!valid) goto read_error;
      ctg_layout[ctg].defined = TRUE;
      ctg_layout[ctg].zoom = zoom;
      ctg_layout[ctg].bury = bury;
    }
    else if(sscanf(oneline, "<track entity=\"%s row_policy=\"%s num_rows=\"%d\" height=\"%d\" anchor_bins=\"%d\" anchor_pos=\"%d\" anchor_lines=\"%d\"", 
            entity, policy, &num_rows, &height, &anchor_bins, &anchor_pos, &anchor_lines)==7){
      if(ctg==-1) goto read_error;
      if(t_info!=NULL) goto read_error;
      if(!valid) goto read_error;
      entity[strlen(entity)-1]='\0';
      policy[strlen(policy)-1]='\0';
      if(ctg_layout[ctg].tracks==NULL){
        if((ctg_layout[ctg].tracks = malloc(sizeof(struct layout_track_info)))==NULL)
          g_error("Memory allocation failed");
        t_info=ctg_layout[ctg].tracks;
      }
      else{
        for(t_info=ctg_layout[ctg].tracks; t_info->next!=NULL; t_info=t_info->next)
          ;
        if((t_info->next = malloc(sizeof(struct layout_track_info)))==NULL)
          g_error("Memory allocation failed");
        t_info=t_info->next;
      }
      t_info->height = height;
      t_info->numrows = num_rows;
      t_info->show_anchor_bins = anchor_bins;
      t_info->show_anchor_pos = anchor_pos;
      t_info->show_anchor_lines = anchor_lines;
      if(!strcmp(entity, "MARKERS"))
        t_info->entity=MARKERS;
      else if(!strcmp(entity, "CLONES"))
        t_info->entity=CLONES;
      else if(!strcmp(entity, "REMARKS"))
        t_info->entity=REMARKS;
      else if(!strcmp(entity, "ANCHORS"))
        t_info->entity=ANCHORS;
      else if(!strcmp(entity, "SEQUENCE"))
        t_info->entity=SEQUENCE;
      else goto read_error;

      if(!strcmp(policy, "AUTO_POLICY"))
        t_info->row_policy=AUTO_POLICY;
      else if(!strcmp(policy, "FIT_POLICY"))
        t_info->row_policy=FIT_POLICY;
      else if(!strcmp(policy, "LIMIT_POLICY"))
        t_info->row_policy=LIMIT_POLICY;
      else goto read_error;
   
      t_info->filters=NULL;
      t_info->next=NULL;
    }
    else if(sscanf(oneline, "<filter name=\"%s remark=\"%s type=\"%d\" status=\"%d\" \
                   chrom=\"%d\" attach=\"%d\" color_choice=\"%s red=\"%d\" green=\"%d\" blue=\"%d\"",
                   name, remark, &type, &status, &chrom, &attach, color, &red, &green, &blue) == 10){
      if(ctg==-1) goto read_error;
      if(t_info==NULL) goto read_error;
      if(!valid) goto read_error;
      name[strlen(name)-1]='\0';
      remark[strlen(remark)-1]='\0';
      color[strlen(color)-1]='\0';

      if(t_info->filters==NULL){
        if((t_info->filters = malloc(sizeof(struct layout_filter_info)))==NULL)
          g_error("Memory allocation failed");
        f_info = t_info->filters;
      }
      else{
        for(f_info=t_info->filters; f_info->next!=NULL; f_info=f_info->next)
          ;
        if((f_info->next = malloc(sizeof(struct layout_filter_info)))==NULL)
          g_error("Memory allocation failed");
        f_info=f_info->next;
      }
      strcpy(f_info->name, name);
      strcpy(f_info->remark, remark);
      f_info->type = type;
      f_info->status = status;
      f_info->chrom = chrom;
      f_info->attachment = attach;
      f_info->color.red=red;
      f_info->color.green=green;
      f_info->color.blue=blue;

      if(!strcmp(color, "HIDE_COLOR"))
        f_info->color_choice=HIDE_COLOR;
      else if(!strcmp(color, "BLACK_COLOR"))
        f_info->color_choice=BLACK_COLOR;
      else if(!strcmp(color, "RED_COLOR"))
        f_info->color_choice=RED_COLOR;
      else if(!strcmp(color, "ORANGE_COLOR"))
        f_info->color_choice=ORANGE_COLOR;
      else if(!strcmp(color, "YELLOW_COLOR"))
        f_info->color_choice=YELLOW_COLOR;
      else if(!strcmp(color, "GREEN_COLOR"))
        f_info->color_choice=GREEN_COLOR;
      else if(!strcmp(color, "BLUE_COLOR"))
        f_info->color_choice=BLUE_COLOR;
      else if(!strcmp(color, "VIOLET_COLOR"))
        f_info->color_choice=VIOLET_COLOR;
      else if(!strcmp(color, "GRAY_COLOR"))
        f_info->color_choice=GRAY_COLOR;
      else if(!strcmp(color, "CUSTOM_COLOR"))
        f_info->color_choice=CUSTOM_COLOR;
      else goto read_error;

      f_info->next=NULL;
    }
    else if(!strcmp(oneline, "</track>")){
      t_info=NULL;
    }
    else if(!strcmp(oneline, "</contig>")){
      t_info=NULL;
      ctg=-1;  
    }
    else if(!strcmp(oneline, "</layout>")){
      valid=FALSE;
    }
    else if(strstr(oneline, "<?xml version")!=NULL){
      ;
    }
    else goto read_error;
  }

  filclose(fppfile);
  return 1;

read_error:
  g_warning("Error occured while reading fpp file.  Will use defaults.\n");
  printf("Last line successfully read: %s\n",oneline);
  filclose(fppfile);
  return 0;
}

/*                     DEF: write_fpp_file
 * Writes the information from the ctg_layout structure to the 
 * fpp file.*/
void
write_fpp_file(){
  FILE	*out ;
  int i;
  BOOL opened = TRUE;
  char entity[50], policy[50], color[50];
  struct layout_track_info *t_info;
  struct layout_filter_info *f_info;

  if(ctg_layout==NULL) load_layout();
  else check_ctg_layout_mem();

  if(dataloaded){
    if(strlen(dirName)>0){
      if((out = fopen(messprintf("%s/%s.fpp", dirName, fileName),"w")) == NULL ){
		printf("File %s/%s.fpp cannot be written.\n", dirName, fileName);
		opened = FALSE;
      }
    }
    else{
      if((out = fopen(messprintf("%s.fpp", fileName),"w")) == NULL ){
		printf("File %s.fpp cannot be written.\n", fileName);
		opened = FALSE;
      }
    }
    if(opened){
      fprintf(out,"<?xml version=\"1.0\"?>\n\n");
      fprintf(out,"<layout help_path=\"%s\" >\n", helpfilepath);
      for(i=0; i<=max_layout; i++){
        if(!ctg_layout[i].defined) continue;
        fprintf(out,"  <contig id=\"%d\" zoom=\"%.1f\" bury=\"%d\">\n",
                i, ctg_layout[i].zoom, ctg_layout[i].bury);
        /* Write out all tracks for ctg*/
        for(t_info=ctg_layout[i].tracks; t_info!=NULL; t_info=t_info->next){
          switch(t_info->entity){
            case MARKERS:
              strcpy(entity, "MARKERS");
              break;
            case CLONES:
              strcpy(entity, "CLONES");
              break;
            case REMARKS:
              strcpy(entity, "REMARKS");
              break;
            case ANCHORS:
              strcpy(entity, "ANCHORS");
              break;
            case SEQUENCE:
              strcpy(entity, "SEQUENCE");
              break;
            case NONE:
              strcpy(entity, "NONE");
              break;
          }
          switch(t_info->row_policy){
            case AUTO_POLICY:
              strcpy(policy, "AUTO_POLICY");
              break;
            case FIT_POLICY:
              strcpy(policy, "FIT_POLICY");
              break;
            case LIMIT_POLICY:
              strcpy(policy, "LIMIT_POLICY");
              break;
          }
          fprintf(out,"    <track entity=\"%s\" row_policy=\"%s\" num_rows=\"%d\" height=\"%d\" anchor_bins=\"%d\" anchor_pos=\"%d\" anchor_lines=\"%d\">\n",
                  entity, policy, t_info->numrows, t_info->height, 
                  t_info->show_anchor_bins, t_info->show_anchor_pos, t_info->show_anchor_lines);
          /* Write out all filters for track*/
          for(f_info=t_info->filters; f_info!=NULL; f_info=f_info->next){
	    switch(f_info->color_choice){
	      case HIDE_COLOR:
		strcpy(color, "HIDE_COLOR");
		break;
	      case BLACK_COLOR:
		strcpy(color, "BLACK_COLOR");
		break;
	      case RED_COLOR:
		strcpy(color, "RED_COLOR");
		break;
	      case ORANGE_COLOR:
		strcpy(color, "ORANGE_COLOR");
		break;
	      case YELLOW_COLOR:
		strcpy(color, "YELLOW_COLOR");
		break;
	      case GREEN_COLOR:
		strcpy(color, "GREEN_COLOR");
		break;
	      case BLUE_COLOR:
		strcpy(color, "BLUE_COLOR");
		break;
	      case VIOLET_COLOR:
		strcpy(color, "VIOLET_COLOR");
		break;
	      case GRAY_COLOR:
		strcpy(color, "GRAY_COLOR");
		break;
	      case CUSTOM_COLOR:
		strcpy(color, "CUSTOM_COLOR");
		break;
            }
            fprintf(out,"      <filter name=\"%s\" remark=\"%s\" type=\"%d\" status=\"%d\" chrom=\"%d\" attach=\"%d\" color_choice=\"%s\" red=\"%d\" green=\"%d\" blue=\"%d\"/>\n",
                    f_info->name, f_info->remark, f_info->type, 
                    f_info->status, f_info->chrom, f_info->attachment, color, 
                    f_info->color.red, f_info->color.green, f_info->color.blue); 
          }
          fprintf(out,"    </track>\n");
        }
        fprintf(out,"  </contig>\n");
      }
      fprintf(out,"</layout>\n");
    }
    filclose(out);
  }
}

/*                     DEF: load_default_layout
 * Element 0 is the default layout for contigs with undefined layouts.
 * Loaded when there is no default element in fpp file or error reading
 * fpp file occured.*/
void
load_default_layout(){
  struct layout_track_info *t;
  struct layout_track_info **pt;
  struct layout_filter_info *f;
  int i,n; 
  CLONE* clp;

  strcpy(helpfilepath, " ");

  ctg_layout[0].defined=TRUE;
  ctg_layout[0].zoom=5.0;
  ctg_layout[0].bury=1;

  if (ctg_layout[0].zoom > zoom_max ) {
    ctg_layout[0].zoom = zoom_max - 1;     
  }

  pt=&(ctg_layout[0].tracks);


  if (1) //arrayMax(markerdata) > 0)
  {
      *pt = (struct layout_track_info*)malloc(sizeof(struct layout_track_info));
      t = *pt;
      pt = &(t->next);
      memset(t,0,sizeof(struct layout_track_info));
      t->entity = MARKERS;
      t->row_policy = FIT_POLICY;
      t->numrows = 0;
      t->show_anchor_bins = 0;
      t->show_anchor_pos = 0;
      t->show_anchor_lines = 0;
      t->height = 90;  /* cari 24.5.4 was 100 */
      t->filters = malloc(sizeof(struct layout_filter_info));
        f=t->filters;
        strcpy(f->name, "*");
        strcpy(f->remark, "");
        f->type = 0;
        f->status = 0;
        f->chrom = 0;
        f->attachment = 0;
        f->color_choice = BLACK_COLOR;
        f->next = NULL;
  }

  if (1) //arrayMax(acedata) > 0)
  {
      *pt = (struct layout_track_info*)malloc(sizeof(struct layout_track_info));
      t = *pt;
      pt = &(t->next);
      memset(t,0,sizeof(struct layout_track_info));

      t->entity = CLONES;
      t->row_policy = FIT_POLICY;
      t->numrows = 0;
      t->show_anchor_bins = 0;
      t->show_anchor_pos = 0;
      t->show_anchor_lines = 0;
      t->height = 280;  /* cari 24.5.4 was 300 */
      t->filters = malloc(sizeof(struct layout_filter_info));
        f=t->filters;
        strcpy(f->name, "*");
        strcpy(f->remark, "");
        f->type = 0;
        f->status = 0;
        f->chrom = 0;
        f->attachment = 0;
        f->color_choice = BLACK_COLOR;
        f->next=NULL;

        f->next = malloc(sizeof(struct layout_filter_info));
        f=f->next;
        strcpy(f->name, "");
        strcpy(f->remark, "");
        f->type = 0;
        f->status = 6; /*Shotgun */
        f->chrom = 0;
        f->attachment = 0;
        f->color_choice = BLUE_COLOR;
        f->next=NULL;

        f->next = malloc(sizeof(struct layout_filter_info));
        f=f->next;
        strcpy(f->name, "");
        strcpy(f->remark, "");
        f->type = 0;
        f->status = 2; /* TILE */
        f->chrom = 0;
        f->attachment = 0;
        f->color_choice = RED_COLOR;
        f->next = NULL;
  }

  if (1) //arrayMax(acedata) > 0)
  {
      n = 0;
      for (i = 0; i < arrayMax(acedata); i++)
      {
        clp = arrp(acedata,i,CLONE);
        if (clp->remark) n++;
      }
      if (1) //n > 0)
      {
          *pt = (struct layout_track_info*)malloc(sizeof(struct layout_track_info));
          t = *pt;
          memset(t,0,sizeof(struct layout_track_info));
          pt = &(t->next);

          t->entity = REMARKS;
          t->row_policy = FIT_POLICY;
          t->numrows = 0;
          t->show_anchor_bins = 0;
          t->show_anchor_pos = 0;
          t->show_anchor_lines = 0;
          t->height = 70;  /* cari 24.5.4 was 75 */
          t->filters = malloc(sizeof(struct layout_filter_info));
            f=t->filters;
            strcpy(f->name, "*");
            strcpy(f->remark, "");
            f->type = 0;
            f->status = 0;
            f->chrom = 0;
            f->attachment = 0;
            f->color_choice = BLACK_COLOR;
            f->next = NULL;
      }
  }

  if (1) //arrayMax(markerdata) > 0)
  {
      *pt = (struct layout_track_info*)malloc(sizeof(struct layout_track_info));
      t = *pt;
      memset(t,0,sizeof(struct layout_track_info));
      pt = &(t->next);

      t->entity = ANCHORS;
      t->row_policy = FIT_POLICY;
      t->numrows = 0;
      t->show_anchor_bins = 0;
      t->show_anchor_pos = 0;
      t->show_anchor_lines = 1;
      t->height = 65;  /* cari 24.5.4 was 68 */
      t->filters = malloc(sizeof(struct layout_filter_info));
        f=t->filters;
        strcpy(f->name, "*");
        strcpy(f->remark, "");
        f->type = 0;
        f->status = 0;
        f->chrom = 0;
        f->attachment = 0;
        f->color_choice = BLACK_COLOR;
        f->next = NULL;

        f->next = malloc(sizeof(struct layout_filter_info));
        f=f->next;
        strcpy(f->name, "*");
        strcpy(f->remark, "");
        f->type = 2;
        f->status = 0;
        f->chrom = 0;
        f->attachment = 0;
        f->color_choice = GRAY_COLOR;
        f->next = NULL;

        if(Proj.label_abbrev[0]!='\0'){  /*Only have this filter if ctg->chr used*/
          f->next = malloc(sizeof(struct layout_filter_info));
          f=f->next;
          strcpy(f->name, "*");
          strcpy(f->remark, "");
          f->type = 0;
          f->status = 0;
          f->chrom = 2;
          f->attachment = 0;
          f->color_choice = RED_COLOR;
          f->next = NULL;
        }
    }

    if (1) //fpc_tree_has_content(&seq_tree) > 0)
    {
      *pt = (struct layout_track_info*)malloc(sizeof(struct layout_track_info));
      t = *pt;
      memset(t,0,sizeof(struct layout_track_info));
      pt = &(t->next);

      t->entity = SEQUENCE;
      t->row_policy = AUTO_POLICY;
      t->numrows = 0;
      t->show_anchor_bins = 0;
      t->show_anchor_pos = 0;
      t->show_anchor_lines = 0;
      t->height = 70;  
      t->filters = malloc(sizeof(struct layout_filter_info));
        f=t->filters;
        strcpy(f->name, "*");
        strcpy(f->remark, "");
        f->type = 0;
        f->status = 0;
        f->chrom = 0;
        f->attachment = 0;
        f->color_choice = BLACK_COLOR;
        f->next = NULL;
    }
}

/*                     DEF: free_track_layout_mem
 * Frees memory for the track layout struct, including any
 * filter structs defined for the track. */
static void 
free_track_layout_mem(struct layout_track_info *t){
  struct layout_track_info *prev;
  struct layout_filter_info *f, *prev2;

  while(t != NULL){
    f=t->filters;
    while(f != NULL){
      prev2 = f;
      f=f->next;
      g_free(prev2);
    }
    t->filters=NULL;
    prev = t;
    t=t->next;
    g_free(prev);
  }
}

/*                     DEF: free_ctg_layout_mem
 * Frees memory for ctg_layout.  Called when a new project is 
 * loaded, removing the old one, in remove_old_project().*/
void 
free_ctg_layout_mem(){
  int i;

  if(ctg_layout==NULL) return;
  for(i=0; i<=max_layout; i++){
    free_track_layout_mem(ctg_layout[i].tracks);
  }
}

/*                     DEF: check_ctg_layout_mem
 * See if we need to allocate more memory for ctg_layout*/
void
check_ctg_layout_mem(){
  int i;

  if(max_layout >= max_contig) return;

  if((ctg_layout=realloc(ctg_layout, (max_contig+1) * sizeof(struct layout_ctg_info)))==NULL) 
    g_error("Memory allocation failed");
  
  for(i=max_layout+1; i<=max_contig; i++){
    ctg_layout[i].defined=FALSE;
    ctg_layout[i].tracks=NULL;
  }
  max_layout=max_contig;
}


/*                     DEF: load_layout
 * Allocate ctg_layout and call functions to fill it*/
void
load_layout(){
  int i;
  int ret_val;

  if((ctg_layout=calloc(max_contig+1,sizeof(struct layout_ctg_info)))==NULL) 
    g_error("Memory allocation failed");

  for(i=0; i<=max_contig; i++){
    ctg_layout[i].defined=FALSE;
    ctg_layout[i].tracks=NULL;
  }

  ret_val = read_fpp_file();
  if(!ret_val || !ctg_layout[0].defined)
    load_default_layout();
  max_layout=max_contig;
}

/*                     DEF: store_single_ctg_layout
 * Store the layout of the current display for ctg*/
void
store_single_ctg_layout(int ctg){
  int i;
  struct layout_track_info *t_info=NULL;
  struct layout_filter_info *f_info=NULL;
  struct filters *f;

  free_track_layout_mem(ctg_layout[ctg].tracks);

  ctg_layout[ctg].defined=TRUE;
  ctg_layout[ctg].zoom=GTK_ADJUSTMENT(zoom_adj)->value;
  ctg_layout[ctg].bury=showburied;
  ctg_layout[ctg].tracks=NULL;
  
  for(i=0; i<track_num; i++){
    /* Get memory*/
    if(ctg_layout[ctg].tracks==NULL){
      if((ctg_layout[ctg].tracks = malloc(sizeof(struct layout_track_info)))==NULL)
        g_error("Memory allocation failed");
      t_info=ctg_layout[ctg].tracks;
    }
    else{
      if((t_info->next = malloc(sizeof(struct layout_track_info)))==NULL)
        g_error("Memory allocation failed");
      t_info=t_info->next;
    }

    t_info->entity = GTK_TRACK(tracks[i])->entity;
    t_info->row_policy = GTK_TRACK(tracks[i])->row_policy;
    t_info->numrows = GTK_TRACK(tracks[i])->numrows;
    t_info->show_anchor_bins = GTK_TRACK(tracks[i])->show_anchor_bins;
    t_info->show_anchor_pos = GTK_TRACK(tracks[i])->show_anchor_pos;
    t_info->show_anchor_lines = GTK_TRACK(tracks[i])->show_anchor_lines;
    t_info->height = tracks[i]->allocation.height;
    t_info->filters=NULL;
    for(f=GTK_TRACK(tracks[i])->filterList; f!=NULL; f=f->next){
      if(f->ignore) continue;
      /* Get memory*/
      if(t_info->filters==NULL){
	if((t_info->filters = malloc(sizeof(struct layout_filter_info)))==NULL)
          g_error("Memory allocation failed");
	f_info = t_info->filters;
      }
      else{
	if((f_info->next = malloc(sizeof(struct layout_filter_info)))==NULL)
          g_error("Memory allocation failed");
	f_info=f_info->next;
      }

      strcpy(f_info->name, f->name);
      strcpy(f_info->remark, f->remark);
      f_info->type = f->type;
      f_info->status = f->status;
      f_info->chrom = f->chrom;
      f_info->attachment = f->attachment;
      f_info->color_choice = f->color_choice;
      f_info->color = f->color;
      f_info->next = NULL;
    }
    t_info->next=NULL;
  }
}
